using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

namespace FileUtility.FTP.FTP
{
	/// <summary>
	/// The purpose of this class is to provide basic asynchronous
	/// (non-blocking) FTP capabilities using call-backs.
	/// </summary>
	/// <remarks>
	/// Programmer:			Edmond Woychowsky
	/// Creation Date:		September 10, 2004
	/// Last Modification:	
	/// </remarks>
	public class Client : FTP
	{
		#region private
		private AsyncCallback m_connectCB;			//	Connect callback method
		private AsyncCallback m_sendCB;				//	Send callback method
		private AsyncCallback m_receiveCB;			//	Receive callback method
		private ManualResetEvent m_send_event;		//	Send threading event
		private ManualResetEvent m_receive_event;	//	Receive threading event
		private StateMaintenance m_state = new StateMaintenance();
		private string m_rnfr_file = "";			//	Rename from file name
		private string m_rnto_file = "";			//	Rename to file name
		#endregion

		#region constructors
		/// <summary>
		/// The purpose of this method is to act as a constructor for this class.
		/// </summary>
		/// <param name="host">FTP Server URI</param>
		public Client(string host) 
		{
			this.m_uri = host.ToString();

			initialize();
		}

		/// <summary>
		/// The purpose of this method is to act as a constructor for this class.
		/// </summary>
		/// <param name="host">FTP Server URI</param>
		/// <param name="user">FTP server user id</param>
		/// <param name="password">FTP server password</param>
		public Client(string host,string user,string password)
		{
			this.m_uri = host.ToString();
			this.m_user = user.ToString();
			this.m_password = password.ToString();

			initialize();
		}
		#endregion

		#region publicProperties
		/// <summary>
		/// The purpose of this property is to get the return code from the last command.
		/// </summary>
		public int returncode 
		{
			get 
			{
				return(this.m_state.returncode);
			}
		}
		#endregion

		#region privateMethods
		/// <summary>
		/// The purpose of this method is to perform common FTP initialization logic.
		/// </summary>
		private void initialize() 
		{
			IPAddress address = Dns.Resolve(this.m_uri).AddressList[0];
			IPEndPoint endPoint = new IPEndPoint(address,DEFAULT_PORT);

			this.m_state.socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
			this.m_connectCB = new AsyncCallback(connectCallBack);
			this.m_sendCB = new AsyncCallback(sendCallBack);
			this.m_receiveCB = new AsyncCallback(receiveCallBack);
			this.m_state.command = CONNECT;

			connect(endPoint,this.m_state);

			switch(user()) 
			{
				case(NEED_PASSWORD):
					if(pass() != LOGGED_IN)
						throw(new Exception(LOGON_ERROR));

					break;
				case(SERVICE_READY):
					receive(this.m_state);

					if(this.m_state.returncode == NEED_PASSWORD)
						if(pass() != LOGGED_IN)
							throw(new Exception(LOGON_ERROR));

					break;
				case(ACTION_OK):
				case(LOGGED_IN):

					break;
				default:
					throw(new Exception(LOGON_ERROR));
			}

			while((this.m_state.returncode == LOGGED_IN) | (this.m_state.returncode == ACTION_OK) | (this.m_state.returncode == SERVICE_READY)) 
			{
				this.m_state.returncode = 0;

				receive(this.m_state);				//	Handle multi-part responses
			}
		}

		/// <summary>
		/// The purpose of this method is to begin an asynchronous request for a 
		/// socket connection.
		/// </summary>
		/// <param name="endPoint">Network endpoint</param>
		/// <param name="state">Connection state</param>
		/// <returns>FTP return code</returns>
		private int connect(IPEndPoint endPoint,StateMaintenance state) 
		{
			StringBuilder command = new StringBuilder();

			this.m_send_event = new ManualResetEvent(false);
			state.callback = this.m_connectCB;

			command.Append("Attempting connection to FTP server...");
			command.Append(CRLF);

			this.record(command);

			try 
			{
				state.socket.BeginConnect(endPoint, state.callback,state);

				this.m_send_event.WaitOne(TIMEOUT,true);

				receive(this.m_state);

				this.record(this.m_state.response);

				return(this.m_state.returncode);
			}
			catch(Exception) 
			{
				throw(new Exception(CONNECTION_ERROR));
			}
		}

		/// <summary>
		/// The purpose of this method is to handle a call back from a request for an 
		/// asynchronous socket connection.
		/// </summary>
		/// <param name="result">Connection state</param>
		private void connectCallBack(IAsyncResult result) 
		{
			try 
			{
				StateMaintenance state = (StateMaintenance)result.AsyncState;

				state.socket.EndConnect(result);

				this.m_send_event.Set();
			}
			catch(Exception e) 
			{
				throw(new Exception(CONNECTION_ERROR, e));
			}
		}

		/// <summary>
		/// The purpose of this method is to send commands and data asynchronously.
		/// </summary>
		/// <param name="state">Connection state</param>
		/// <param name="data">Command string</param>
		private void sendCommand(StateMaintenance state,StringBuilder data) 
		{
			sendCommand(state, data.ToString());
		}

		/// <summary>
		/// The purpose of this method is to send commands and data asynchronously.
		/// </summary>
		/// <param name="state">Connection state</param>
		/// <param name="data">Command string</param>
		private void sendCommand(StateMaintenance state,string data) 
		{
			this.m_send_event = new ManualResetEvent(false);
			state.callback =  this.m_sendCB;

			state.command = data;					//	Set command

			this.record(state.command);				//	Record command to log
			this.record(CRLF);

			state.socket.BeginSend(state.bytes,0,state.bytes.Length,SocketFlags.None,state.callback,state);

			this.m_send_event.WaitOne(TIMEOUT,true);
		}

		/// <summary>
		/// The purpose of this method is to handle a call back from an asynchronous 
		/// send.
		/// </summary>
		/// <param name="result">Connection state</param>
		private void sendCallBack(IAsyncResult result) 
		{
			try 
			{
				StateMaintenance state = (StateMaintenance) result.AsyncState;

				int bytes = state.socket.EndSend(result);

				this.m_send_event.Set();
			}
			catch(Exception) { }
		}

		/// <summary>
		/// The purpose of this method is to receive data asynchronously.
		/// </summary>
		/// <param name="state">Connection state</param>
		private void receive(StateMaintenance state) 
		{
			this.m_receive_event = new ManualResetEvent(false);
			state.callback = this.m_receiveCB;

			state.reset();

			try 
			{
				state.socket.BeginReceive(state.buffer,0,state.buffer.Length,0,state.callback,state);

				this.m_receive_event.WaitOne(TIMEOUT,true);

				if(!this.m_state.socket.Equals(state.socket))
					state.socket.Close();			//	Close data transfer socket
			}
			catch(Exception e) 
			{
				while(e != null) 
				{
					Console.WriteLine(e.ToString());

					e = e.InnerException;
				}
			}
		}

		/// <summary>
		/// The purpose of this method is to handle a call back from an asynchronous 
		/// receive.
		/// </summary>
		/// <param name="result">Connection state</param>
		private void receiveCallBack(IAsyncResult result) 
		{
			try 
			{
				StateMaintenance state = (StateMaintenance)result.AsyncState;
				Regex re = new Regex("$");			//	Make commands 5 bytes
				StringBuilder terminate = new StringBuilder();
				string command = re.Replace(state.command,"  ");
				int bytes = state.socket.EndReceive(result);

				re = new Regex(@"\s{1,}");
				command = re.Replace(command,"  ");

				if(bytes > 0) 
					state.response = Encoding.ASCII.GetString(state.buffer,0,bytes);

				terminate.Append(state.buffer[bytes - 2].ToString());
				terminate.Append(state.buffer[bytes - 1].ToString());

				switch(command.Substring(0,5)) 
				{
					case CONNECT:					//	Connect receive handler
						if(state.returncode != SERVICE_READY)
							throw(new Exception(CONNECTION_ERROR));

						if(terminate.ToString() == EOL)
							this.m_receive_event.Set();
						else
							state.socket.BeginReceive(state.buffer,0,state.buffer.Length,0,state.callback,state);

						break;
					case ABOR:						//	Command receive handler
					case ACCT:
					case APPE:
					case CDUP:
					case CWD:
					case DELE:
					case HELP:
					case LIST:
					case MDTM:
					case MKD:
					case MODE:
					case NOOP:
					case PASS:
					case PASV:
					case PORT:
					case PWD:
					case QUIT:
					case REIN:
					case RETR:
					case RMD:
					case RNFR:
					case RNTO:
					case SITE:
					case SIZE:
					case STAT:
					case STOR:
					case SYST:
					case STOU:
					case STRU:
					case TYPE:
					case USER:
						this.record(state.response);

						if(terminate.ToString() == EOL)
							this.m_receive_event.Set();
						else
							state.socket.BeginReceive(state.buffer,0,state.buffer.Length,0,state.callback,state);

						break;
					default:						//	Data receive handler
						if(terminate.ToString() == EOL)
							this.m_receive_event.Set();
						else
							state.socket.BeginReceive(state.buffer,0,state.buffer.Length,0,state.callback,state);

						break;
				}
			}
			catch(Exception) { }					//	Deal with errors later
		}

		/*
		 * Method:			socketConnect
		 * Programmer:		Edmond Woychowsky
		 * Creation Date:	January 25, 2005
		 * Description:		The purpose of this method is to send an create an instance
		 *					of StateMaintenance with a connected socket based upon the
		 *					last PASV or PORT command.
		 */
		/// <summary>
		/// The purpose of this method is to send an create an instance of 
		/// StateMaintenance with a connected socket based upon the last PASV or PORT 
		/// command.
		/// </summary>
		/// <returns>Connection state</returns>
		private StateMaintenance socketConnect() 
		{
			StateMaintenance state = new StateMaintenance();

			try 
			{
				IPAddress address = Dns.Resolve(this.m_uri).AddressList[0];
				IPEndPoint endPoint = new IPEndPoint(address,dataPort());

				state.socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

				state.socket.Connect(endPoint);
			}
			catch(Exception e) 
			{
				throw(new Exception(SOCKET_ERROR, e));
			}

			return(state);
		}
		#endregion

		#region publicMethods
		/// <summary>
		/// The purpose of this method is to abort the current operation.
		/// </summary>
		/// <returns>FTP command result</returns>
		public string abor() 
		{
			sendCommand(this.m_state,ABOR);			//	Send command
			receive(this.m_state);					//	Receive response

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to append to the end of a file on the remote 
		/// host.
		/// </summary>
		/// <param name="file">File name</param>
		/// <returns>FTP command result</returns>
		public string appe(string file) 
		{
			Stream input = File.OpenRead(file);

			appe(file,input);

			input.Close();

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to append to the end of a file on the remote 
		/// host.
		/// </summary>
		/// <param name="localFile">Local file name</param>
		/// <param name="remoteFile">Remote file name</param>
		/// <returns>FTP command result</returns>
		public string appe(string localFile,string remoteFile) 
		{
			Stream input = File.OpenRead(localFile);

			appe(remoteFile,input);

			input.Close();

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to append to the end of a file on the remote 
		/// host.
		/// </summary>
		/// <param name="localFile">Local file name</param>
		/// <param name="stream">File stream</param>
		/// <returns>FTP command result</returns>
		public string appe(string remoteFile, Stream stream) 
		{
			StateMaintenance state = socketConnect();
			StringBuilder command = new StringBuilder();
			byte[] buffer = new byte[state.BUFFER_SIZE];
			int length = 0;

			command.Append(APPE);					//	Build command
			command.Append(remoteFile);

			sendCommand(this.m_state,command);
			receive(this.m_state);					//	Receive response

			if(this.m_state.returncode == TRANSFER_STARTING) 
			{
				stream.Position = 0;				//	Start of stream

				while((length = stream.Read(buffer,0,state.BUFFER_SIZE)) > 0)
					state.socket.Send(buffer,length,0);

				state.socket.Close();

				receive(this.m_state);				//	Receive response
			}

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to change the current working directory on the 
		/// host to the parent directory.
		/// </summary>
		/// <returns>FTP command result</returns>
		public string cdup() 
		{
			sendCommand(this.m_state,CDUP);			//	Send command
			receive(this.m_state);					//	Receive response

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to change the current working directory.
		/// </summary>
		/// <param name="directory">Path to change to</param>
		/// <returns>FTP command result</returns>
		public string cwd(string directory) 
		{
			Regex re = new Regex(@"\s{2,}$");		//	Replace multiple whitespaces
			StringBuilder command = new StringBuilder();
			int count = RETRIES;					//	Retry count

			command.Append(re.Replace(CWD," "));	//	Build command
			command.Append(directory);

			do 
			{
				sendCommand(this.m_state,command);
				receive(this.m_state);

				--count;
			} while((this.m_state.returncode != ACTION_OK) & (count > 0));

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to delete a file on the remote server.
		/// </summary>
		/// <param name="file">Name of file to delete</param>
		/// <returns>FTP command result</returns>
		public string dele(string file) 
		{
			StringBuilder command = new StringBuilder();

			command.Append(DELE);					//	Build command
			command.Append(file);

			sendCommand(this.m_state,command);
			receive(this.m_state);					//	Receive response

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to obtain FTP command help from the remote host.
		/// </summary>
		/// <returns>FTP command result</returns>
		public string help() 
		{
			return(help(null));
		}

		/// <summary>
		/// The purpose of this method is to obtain FTP command help from the remote host.
		/// </summary>
		/// <param name="command">Command for which to obtain help</param>
		/// <returns>FTP command result</returns>
		public string help(string command) 
		{
			StringBuilder helpCommand = new StringBuilder();

			helpCommand.Append(HELP);				//	Build command
			helpCommand.Append(command);

			sendCommand(this.m_state,helpCommand);

			do 
			{
				this.m_state.returncode = 0;

				receive(this.m_state);				//	Receive response
			} while(this.m_state.returncode != 0);

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to return a file listing of the current working
		/// directory.
		/// </summary>
		/// <returns>FTP command result</returns>
		public string list() 
		{
			StateMaintenance state = socketConnect();

			sendCommand(this.m_state,LIST);

			do 
			{
				this.m_state.returncode = 0;

				receive(this.m_state);
			} while((this.m_state.returncode == TRANSFER_STARTING) | (this.m_state.returncode == FILE_STATUS_OK));

			state.command = DATA;					//	Data receive command
			receive(state);							//	Receive data

			state.socket.Close();
			this.record(state.response);

			return(state.response);
		}

		/// <summary>
		/// The purpose of this method is to return the modification date/time of a file.
		/// </summary>
		/// <param name="file">Remote host file name</param>
		/// <returns>FTP command result</returns>
		public string mdtm(string file) 
		{
			StringBuilder command = new StringBuilder();

			command.Append(MDTM);					//	Build command
			command.Append(file);

			sendCommand(this.m_state,command);
			receive(this.m_state);					//	Receive response

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to create a directory on the remote server.
		/// </summary>
		/// <param name="directory">Name of directory to create on the remote host.</param>
		/// <returns>FTP command result</returns>
		public string mkd(string directory) 
		{
			StringBuilder command = new StringBuilder();

			command.Append(MKD);					//	Build command
			command.Append(directory);

			sendCommand(this.m_state,command);
			receive(this.m_state);					//	Receive response

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to return a filtered file list.
		/// </summary>
		/// <param name="mask">File name filter</param>
		/// <returns>FTP command result</returns>
		public string nlst(string mask) 
		{
			StateMaintenance state = socketConnect();
			StringBuilder command = new StringBuilder();

			command.Append(NLST);					//	Build command
			command.Append(mask);

			sendCommand(this.m_state,command);		//	Send command
			receive(this.m_state);					//	Receive response

			state.command = DATA;					//	Data receive
			receive(state);							//	Receive data
			
			receive(this.m_state);					//	Receive response
			state.socket.Close();
			this.record(state.response);

			return(state.response);
		}

		/// <summary>
		/// The purpose of this method is to execute an FTP no operation on the remote 
		/// server.
		/// </summary>
		/// <returns>FTP command result</returns>
		public string noop() 
		{
			sendCommand(this.m_state,NOOP);			//	Send command
			receive(this.m_state);					//	Receive response

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to send the password to the remote host.
		/// </summary>
		/// <returns>FTP command result</returns>
		public int pass() 
		{
			return(pass(this.m_password));
		}

		/// <summary>
		/// The purpose of this method is to send the password to the remote host.
		/// </summary>
		/// <param name="password">Remote host password</param>
		/// <returns>FTP command result</returns>
		public int pass(string password) 
		{
			StringBuilder command = new StringBuilder();

			this.m_password = password;

			command.Append(PASS);					//	Build command
			command.Append(password);

			sendCommand(this.m_state,command);

			receive(this.m_state);					//	Receive response

			return(this.m_state.returncode);
		}

		/// <summary>
		/// The purpose of this method is to enter passive transfer mode.
		/// </summary>
		/// <returns>FTP command result</returns>
		public string pasv() 
		{
			int count = RETRIES;					//	Retry count

			this.m_state.returncode = 0;

			do 
			{
				--count;							//	Decrement try counter

				sendCommand(this.m_state,PASV);		//	Send passive command

				if(this.m_state.returncode != PASSIVE_MODE)
					receive(this.m_state);			//	Receive response
			} while((this.m_state.returncode != PASSIVE_MODE) & (count > 0));


			if(this.m_state.returncode != PASSIVE_MODE)
				throw(new Exception(this.m_state.error()));
			else 
			{
				Regex re = new Regex(@"^.{0,}\(");	//	Regular expression
				StringBuilder address = new StringBuilder();
				string[] values;					//	Address parts
				string work = re.Replace(this.m_state.response,"");

				re = new Regex(@"\).{0,}\r\n$");

				work = re.Replace(work,"");

				re = new Regex(@",");

				values = re.Split(work);			//	Isolate address/port

				for(int i=0;i < 4;i++) 
				{
					address.Append(values[i]);

					if(i != 3)
						address.Append(".");
				}

				ipAddress = address.ToString();

				dataPort(values[4],values[5]);
			}

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to return the full path of the current working 
		/// directory.
		/// </summary>
		/// <returns>FTP command result</returns>
		public string pwd() 
		{
			sendCommand(this.m_state,PWD);			//	Send command
			receive(this.m_state);					//	Receive response

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to send an FTP QUIT command to the remote host.
		/// </summary>
		/// <returns>FTP command result</returns>
		public string quit() 
		{
			try 
			{
				sendCommand(this.m_state,QUIT);		//	Send command
				receive(this.m_state);				//	Receive response

				this.m_state.close();
			}
			catch(Exception) { }

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to re-initialize the connection to the remote 
		/// server.
		/// </summary>
		/// <returns>FTP command result</returns>
		public string rein() 
		{
			sendCommand(this.m_state,REIN);			//	Send command
			receive(this.m_state);					//	Receive response

			return(this.m_state.response);
		}

		/// <summary>
		/// he purpose of this method is to download a file from the remote server.
		/// </summary>
		/// <param name="file">File name to retrieve</param>
		/// <returns>FTP command result</returns>
		public string retr(string file) 
		{
			StateMaintenance state = socketConnect();
			StringBuilder command = new StringBuilder();

			command.Append(RETR);					//	Build command
			command.Append(file);

			sendCommand(this.m_state,command);

			do 
			{
				this.m_state.returncode = 0;		//	Avoid infinite loop

				receive(this.m_state);				//	Receive response, if any
			} while((this.m_state.returncode == TRANSFER_STARTING) | (this.m_state.returncode == FILE_STATUS_OK));

			state.command = DATA;					//	Data receive command
			receive(state);							//	Receive data

			state.socket.Close();					//	Receive complete

			return(state.response);
		}

		/// <summary>
		/// The purpose of this method is to delete a directory on the remote server.
		/// </summary>
		/// <param name="directory">Name of the directory to remove</param>
		/// <returns>FTP command result</returns>
		public string rmd(string directory) 
		{
			StringBuilder command = new StringBuilder();

			command.Append(RMD);					//	Build command
			command.Append(directory);

			sendCommand(this.m_state,command);
			receive(this.m_state);					//	Receive response

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to specify the rename from part of a file 
		/// rename.
		/// </summary>
		/// <param name="file">Original name of file to rename</param>
		/// <returns>FTP command result</returns>
		public string rnfr(string file) 
		{
			StringBuilder command = new StringBuilder();

			this.m_rnfr_file = file;

			command.Append(RNFR);					//	Build command
			command.Append(this.m_rnfr_file);

			sendCommand(this.m_state,command);
			receive(this.m_state);					//	Receive response

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to specify the rename to part of a file rename.
		/// </summary>
		/// <param name="file">New name of file to rename</param>
		/// <returns>FTP command result</returns>
		public string rnto(string file) 
		{
			StringBuilder command = new StringBuilder();

			this.m_rnto_file = file;

			command.Append(RNFR);					//	Build command
			command.Append(this.m_rnto_file);

			sendCommand(this.m_state,command);

			do
			{
				receive(this.m_state);				//	Receive response
			} while(this.m_state.returncode == PENDING);

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to issue a site specific command on the remote 
		/// server.
		/// </summary>
		/// <param name="command">The site specific command</param>
		/// <returns>FTP command result</returns>
		public string site(string command) 
		{
			StringBuilder siteCommand = new StringBuilder();

			siteCommand.Append(SITE);				//	Build command
			siteCommand.Append(command);

			sendCommand(this.m_state,siteCommand);
			receive(this.m_state);					//	Receive response

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to return the size (in bytes) of the file 
		/// specified.
		/// </summary>
		/// <param name="file">Name of the file on the remote host</param>
		/// <returns>The file size in bytes or zero</returns>
		public int size(string file) 
		{
			StringBuilder command = new StringBuilder();
			int fileSize = 0;

			command.Append(SIZE);
			command.Append(file);

			sendCommand(this.m_state,command);
			receive(this.m_state);

			if(this.m_state.returncode == FILE_STATUS)
				fileSize = int.Parse(this.m_state.response.Substring(4));

			if(fileSize < 0)
				fileSize *= -1;

			return(fileSize);
		}

		/// <summary>
		/// The purpose of this method is to obtain the host server's status.
		/// </summary>
		/// <returns>FTP command result</returns>
		public string stat() 
		{
			sendCommand(this.m_state,STAT);			//	Send command

			receive(this.m_state);					//	Receive response

			if(this.m_state.returncode == STATUS_OK)
				receive(this.m_state);

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to upload the specified file to the remote 
		/// server.
		/// </summary>
		/// <param name="file">Local/remote file name</param>
		/// <returns>FTP command result</returns>
		public string stor(string file) 
		{
			Stream input = File.OpenRead(file);

			stor(file,input);

			input.Close();

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to upload the specified file to the remote 
		/// server.
		/// </summary>
		/// <param name="file">Remote file name</param>
		/// <param name="stream">File stream</param>
		/// <returns>FTP command result</returns>
		public string stor(string file, Stream stream) 
		{
			StateMaintenance state = socketConnect();
			StringBuilder command = new StringBuilder();
			byte[] buffer = new byte[state.BUFFER_SIZE];
			int length = 0;

			command.Append(STOR);					//	Build command
			command.Append(file);

			sendCommand(this.m_state,command);
			receive(this.m_state);					//	Receive response

			if(this.m_state.returncode == TRANSFER_STARTING) 
			{
				stream.Position = 0;				//	Beginning of stream

				while((length = stream.Read(buffer,0,state.BUFFER_SIZE)) > 0)
					state.socket.Send(buffer,length,0);

				state.socket.Close();

				receive(this.m_state);				//	Receive response
			}

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to upload the specified file to the remote 
		/// server.
		/// </summary>
		/// <param name="file">Local file name</param>
		/// <returns>FTP command result</returns>
		public string stou(string file) 
		{
			Stream input = File.OpenRead(file);

			stou(input);

			input.Close();

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to upload the specified file to the remote 
		/// server.
		/// </summary>
		/// <param name="stream">File stream</param>
		/// <returns>FTP command result</returns>
		public string stou(Stream stream) 
		{
			StateMaintenance state = socketConnect();
			byte[] buffer = new byte[state.BUFFER_SIZE];
			int length = 0;

			sendCommand(this.m_state,STOU);			//	Send command

			if(this.m_state.returncode == TRANSFER_STARTING) 
			{
				stream.Position = 0;				//	Start of stream

				while((length = stream.Read(buffer,0,state.BUFFER_SIZE)) > 0)
					state.socket.Send(buffer,length,0);

				state.socket.Close();

				receive(this.m_state);				//	Receive response
			}

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to obtain the host server's system type.
		/// </summary>
		/// <returns>FTP command result</returns>
		public string syst() 
		{
			sendCommand(this.m_state,SYST);			//	Send command
			receive(this.m_state);					//	Receive response

			return(this.m_state.response);
		}

		/// <summary>
		/// The purpose of this method is to send the user name to the remote host.
		/// </summary>
		/// <returns>Integer FTP command return code</returns>
		public int user() 
		{
			return(user(this.m_user));
		}

		/// <summary>
		/// The purpose of this method is to send the user name to the remote host.
		/// </summary>
		/// <param name="userName">Remote host logon id/user name</param>
		/// <returns>Integer FTP command return code</returns>
		public int user(string userName) 
		{
			StringBuilder command = new StringBuilder();

			this.m_user = userName;

			command.Append(USER);					//	Build command
			command.Append(this.m_user);

			sendCommand(this.m_state,command);
			receive(this.m_state);					//	Receive response

			return(this.m_state.returncode);
		}
		#endregion
	}
}
